﻿using System.Diagnostics;
using EPiServer;
using EPiServer.Filters;
using EPiServer.Web.WebControls;
using EPiServer.Core;
using System.Web.UI;
using System.ComponentModel;
using System.Linq;
using TemplateFoundation.PageTypes;

namespace TemplateFoundation.WebControls
{
    /// <summary>
    /// PageTree control based on EPiServer PageTree, but with with additional content templates
    /// </summary>
    public class PageTree : EPiServer.Web.WebControls.PageTree
    {
        PageDataCollection _topLevelpages;

        /// <summary>
        /// Creates a new PageTree control
        /// </summary>
        public PageTree()
        {
            // If not set the PageTemplateContainer.HasChildren property always returns true
            EvaluateHasChildren = true;
        }

        /// <summary>
        /// Gets all pages beneath the specified PageLink
        /// </summary>
        protected virtual PageDataCollection TopLevelPages
        {
            get
            {
                if (_topLevelpages==null)
                {
                    // Get all top level pages (everything beneath the specified PageLink property) that are visible to site visitors in the menu
                    _topLevelpages = FilterForVisitor.Filter(
                        new PageDataCollection(
                            DataFactory.Instance.GetChildren(PageLink)
                                .OfType<PageTypeBase>()
                                .Where(p => p.VisibleInMenu)));
                }

                return _topLevelpages;
            }
        }

        #region Template selectors

        /// <summary>
        /// Instantiates the item template.
        /// </summary>
        /// <param name="template">The template.</param>
        protected override void InstantiateItemTemplate(PageTemplateContainer template)
        {
            if (template.HasChildren)
            {
                template.InstantiateWithFallback(new[] { ItemWithChildrenTemplate, ItemTemplate });
            }
            else
            {
                base.InstantiateItemTemplate(template);
            }
        }

        /// <summary>
        /// Instantiates the top template.
        /// </summary>
        /// <param name="template">The template.</param>
        protected override void InstantiateTopTemplate(PageTemplateContainer template)
        {
            if (template.HasChildren)
            {
                template.InstantiateWithFallback(new[] { TopWithChildrenTemplate, ItemWithChildrenTemplate, ItemTemplate });
            }
            else
            {
                base.InstantiateTopTemplate(template);
            }
        }

        /// <summary>
        /// Instantiates the selected top template.
        /// </summary>
        /// <param name="template">The template.</param>
        protected override void InstantiateSelectedTopTemplate(PageTemplateContainer template)
        {
            if (template.HasChildren)
            {
                template.InstantiateWithFallback(new[] { SelectedTopWithChildrenTemplate, TopWithChildrenTemplate, ItemWithChildrenTemplate, ItemTemplate });
            }
            else
            {
                base.InstantiateSelectedTopTemplate(template);
            }
        }

        /// <summary>
        /// Expanded items are rendered as selected if they have no visible children
        /// </summary>
        /// <param name="template"></param>
        protected override void InstantiateExpandedItemTemplate(PageTemplateContainer template)
        {
            if (!HasVisibleChildren(template))
            {
                base.InstantiateItemTemplate(template);
            }
            else
            {
                base.InstantiateExpandedItemTemplate(template);
            }
        }

        /// <summary>
        /// Instantiates the selected expanded item template.
        /// </summary>
        /// <param name="template">The template.</param>
        protected override void InstantiateSelectedExpandedItemTemplate(PageTemplateContainer template)
        {
            if (!HasVisibleChildren(template))
            {
                base.InstantiateSelectedItemTemplate(template);
            }
            else
            {
                base.InstantiateSelectedExpandedItemTemplate(template);
            }
        }

        /// <summary>
        /// Verifies at least one child page is visible in menus
        /// </summary>
        /// <param name="template"></param>
        /// <returns></returns>
        protected bool HasVisibleChildren(PageTemplateContainer template)
        {
            if (!template.HasChildren)
                return false;

            // If HasChildren returns true we confirm it has at least one child visible in menus
            var page = template.DataItem as PageData;

            if (page==null)
                return false;

            return DataFactory.Instance.GetChildren(page.PageLink).Where(p => p.VisibleInMenu).Any();
        }

        #endregion

        /// <summary>
        /// Checks if a template is for the last top item
        /// </summary>
        /// <param name="template">Can be a PageTemplateContainer or PageData object, usually Container or Container.DataItem</param>
        /// <returns>True if this is the last rendered top template</returns>
        public bool IsLastTopItem(object template)
        {
            if (TopLevelPages==null || !TopLevelPages.Any())
            {
                return false;
            }

            var page = template as PageData;

            if (page == null && template is PageTemplateContainer)
            {
                page = ((PageTemplateContainer)template).DataItem as PageData;
            }

            if (page==null)
            {
                return false;
            }

            return page.PageLink.ID == TopLevelPages.Last().PageLink.ID;
        }

        /// <summary>
        /// Checks if a template is for the first top item
        /// </summary>
        /// <param name="template">Can be a PageTemplateContainer or PageData object, usually Container or Container.DataItem</param>
        /// <returns>True if this is the last rendered top template</returns>
        public bool IsFirstTopItem(object template)
        {
            if (TopLevelPages==null || !TopLevelPages.Any())
            {
                return false;
            }

            var page = template as PageData;

            if (page == null && template is PageTemplateContainer)
            {
                page = ((PageTemplateContainer)template).DataItem as PageData;
            }

            if (page==null)
            {
                return false;
            }

            return page.PageLink.ID == TopLevelPages.First().PageLink.ID;
        }

        #region Templates
        /// <summary>
        /// Gets or sets the item with children template.
        /// </summary>
        /// <value>The item with children template.</value>
        [TemplateContainer(typeof(PageTemplateContainer)), Browsable(false), PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate ItemWithChildrenTemplate { get; set; }

        /// <summary>
        /// Gets or sets the top with children template.
        /// </summary>
        /// <value>The top with children template.</value>
        [TemplateContainer(typeof(PageTemplateContainer)), Browsable(false), PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate TopWithChildrenTemplate { get; set; }

        /// <summary>
        /// Gets or sets the selected top with children template.
        /// </summary>
        /// <value>The selected top with children template.</value>
        [TemplateContainer(typeof(PageTemplateContainer)), Browsable(false), PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate SelectedTopWithChildrenTemplate { get; set; }

        #endregion
    }
}
